Repository navigation
Add pre-session billing and cost notice - #436
AchlysChang wants to merge 1 commit into
Conversation
9d281e8 to
9c008bf
Compare
9c008bf to
9e6ab86
Compare
jserv
left a comment
There was a problem hiding this comment.
Avoid ambiguous references such as Refs #161. Complete the implementation and close the issue properly.
jserv
left a comment
There was a problem hiding this comment.
CI fails on the indent gate. Run make indent, then amend and force-push.
|
@AchlysChang To settle the two requests about the issue reference: this PR covers the pre-session cost warning accepted on #161 on 2026-10-12, while the session length cap and the text-only toggle stay open there, so it does not close #161 and |
2bfb083 to
bd7460d
Compare
jserv
left a comment
There was a problem hiding this comment.
Replace Refs #161 in git commit messages with Close #. Don’t repeat the same mistakes.
e0ad75a to
1c0bfeb
Compare
|
Hi @jserv, regarding the commit message reference: yesterday you mentioned that since the session length cap and text-only toggle remain open, 'Refs #161 stays. The later request to close the issue is withdrawn.' (and also noted this in Issue #161). |
Change to |
My instruction referred to the body of Git commit messages. You must fully resolve Issue #161 and include |
jserv
left a comment
There was a problem hiding this comment.
Before asking someone to review, you MUST resolve any regressions flagged by GitHub Actions.
1c0bfeb to
aa4985d
Compare
aa4985d to
f750c38
Compare
An interview runs on Gemini Live, and its report, interim reviews and phase judge run on the same keys, all billed to the Google AI project the interview runs on; nothing told the operator or the candidate so before it started. The Setup page now says so beside the key, including that a LiveKit provider with Google keys of its own bills its rooms to those, and the lobby names who pays and what reaches Gemini Live besides the text of the interview: voice and video or voice, plus the drawing whenever the interviewer reads it if example drawing is on, or voice and board images at a whiteboard. /api/session reports candidateVideo only when this process hosts the interviewer and null otherwise, since the web half of a split deployment cannot see the agent's settings, and the lobby shows the notice only when it knows. This is the pre-session notice sysprog21#161 asks for; its session length cap and text-only mode stay open there.
f750c38 to
0cf5692
Compare
| <fieldset> | ||
| <legend>Google AI <span class="requirement">Optional</span></legend> | ||
| <p class="group-note">Add a key if this server will host the interviewer.</p> | ||
| <p class="group-note">Gemini Live usage is billed on the whole context of the session, to the Google AI project of the key an interview runs on: this key, unless the interview's LiveKit provider sets Google keys of its own. Retained audio and images cost again on every later turn. The reports, interim reviews and phase judge run on the same keys as the interview and are billed to the same project.</p> |
There was a problem hiding this comment.
This holds only for a single key or keys in one project. ApiSurface::Live and ApiSurface::Report pick keys independently with separate cooldowns, and docs/providers.md says report failover leaves the Live key alone. With GOOGLE_API_KEYS spanning two projects, a report can rotate to the second key while Live stays on the first, so it bills a different project. Say that they draw from the same key list and each request is billed to the project owning the key it used, and update the matching assertion in setup-page.test.js.
| Jim reads it: each `read_board` call sends the current example JPEG, which then | ||
| stays in the context like any other image. The Setup page says the same beside | ||
| the Google API key, naming that key's project unless the interview's LiveKit | ||
| provider sets Google keys of its own, and that the final report, the quiet-pause |
There was a problem hiding this comment.
Same overstatement as the Setup text: "run on the same report model and keys as the interview, so they are billed to the same project" is wrong once the key list spans projects, because the Report surface fails over on its own. Reword it to match the corrected Setup text.
| } catch { | ||
| // A server that cannot answer about accounts is not one that will mint a | ||
| // token either, but the editor still works offline, so do not lock the page. | ||
| // Nor will it bill one, so a notice from an earlier answer comes down. |
There was a problem hiding this comment.
This comment is not true: a failed /api/session leaves Start enabled, and the interview can still navigate and get a token from a server that bills Gemini. The notice then disappears when it is still needed. If hiding it on failure is the policy, say the reason is that we cannot tell who pays, not that nothing will be billed.
jserv
left a comment
There was a problem hiding this comment.
Rebase onto the latest main branch, fix any regressions detected by GitHub Actions, and address the review comments.
| font-size: 0.8125rem; | ||
| line-height: 1.35; | ||
| } | ||
| } |
There was a problem hiding this comment.
The test the longest billing notice keeps the lobby on one 1280x800 screen still fails at this head in the browser gate: with the system font the page is 808px tall against an 800px viewport, and the notice is 122px high, so this rule does not buy the room the comment above it claims. Shorten what the longest notice says or tighten the Start column further, and confirm against the CI system font rather than only the overridden metrics.
An interview runs on Gemini Live, which bills the Google AI project the interview runs on for the whole context of the session: retained audio and images are paid for again on every later turn (
docs/provider-cost-and-degradation.md, "What an interview spends"). The final report, the quiet-pause interim reviews and the phase judge run on the same report model and keys, so they are billed to the same project. Neither the operator entering a key nor the candidate pressing Start was told so. This adds the pre-session notice #161 asks for; its session length cap and text-only mode stay open there.Which project pays is the interview's, not always the server's:
agent_config_forswaps in a LiveKit provider's own Google keys when it has any, so its rooms bill its project (docs/providers.md, "Gemini credential failover"). The wording holds for both. The Setup page says, in its Google AI section, that Gemini Live is billed to the project of the key an interview runs on, this key unless the interview's LiveKit provider sets Google keys of its own, and that the reports, interim reviews and phase judge run on the same keys and are billed to the same project.The lobby shows a notice above Start, linked through
aria-describedby, that says Gemini Live usage is billed on the whole context of the session to the Google AI project this interview runs on, and names what the chosen mode sends besides the text of the interview: voice and video for a coding interview with candidate video enabled, voice without it, and voice and board images at a whiteboard, where the camera is off but every board reaches Gemini as a realtime image on the same stream ("What a whiteboard interview adds"). In a coding interview with example drawing checked it also names the drawing, sent whenever Jim reads it: eachread_boardcall sends the current example JPEG, which then stays in the billed context. Switching mode or toggling example drawing updates it.The notice lists media against "the text of the interview" rather than claiming to be everything sent, because which text reaches the model depends on the mode, the loop and the candidate's consent: the code in a coding interview, which reaches the model as text and is resent on a reconnect, and, outside a coding-only session, any resume or job description snippets the candidate selected and agreed to send, built into the instructions of every generation. The doc paragraph in "What the candidate sees" spells that text out.
/api/sessiongainscandidateVideo, answered by the room dispatcher:LocalDispatcherreports its agent config's setting, and any other dispatcher, or none, reportsnull. A web-only host cannot see the camera setting of an agent that joins from elsewhere, so it promises nothing, and the lobby keeps the notice hidden while the value isnull, before the response arrives, and in offline practice when the request fails or a later refresh does.The longest notice wraps to seven lines in the Start column, which put the 1280x800 lobby at 804px with taller font metrics, so the laptop media query sets the notice smaller and tighter. A lobby test of its own measures the page with that notice showing under the same three fonts and long title as the existing one-screen test, which is unchanged and runs with the notice hidden; the test fails at 804px without the rule.
Browser tests cover each mode, the switch between them, toggling and restoring example drawing, a null or missing value, a failed request and a failed refresh, and wait for the account status that
/api/sessionsets rather than for the initial "Checking account..." text; the Setup page test checks both billing sentences.tests/web/accounts.rscheckscandidateVideoas true, false and null in both the signed-out and the signed-in response, with null both from a dispatcher that does not know and from no dispatcher at all; a unit test coversLocalDispatcherreporting its config.UI Verification
Setup page (Google AI section):

Lobby — Coding mode (candidate video disabled / default):

Lobby — Coding mode (candidate video enabled):

Lobby — Coding mode (candidate video enabled + example drawing checked):

Lobby — Whiteboard mode:
